/**********************************************************************
 *File		Name		:	mo_button.c
 *Creat		Time		:	2022/6/3
 *Program	Author		:	Bryan He（贺璧）
 *File		Discreption	:
 *
 ************************************************************************/
#include <stdio.h>
#include "mo_button.h"

static btn_task_t btn_tsk = {0};
// const mo_vk_code_t vk_table[] = VK_TABLE_;
const mo_btn_event_map_t btn_ev_map[] = INPUT_EVENT_MAP;
const mo_btn_timing_t btn_timeing = BTN_TIMING_TABLE;

#if (HW_NUMBER_)
static btn_widget_t btn_widget[(HW_NUMBER_)] = {0};
#endif

mo_task mo_get_btn_task(void) { return &btn_tsk.tsk; }
static btn_widget_t *mo_get_vk_widget_by_code(mo_vk_code_t vk_c) {
    btn_widget_t *widget = NULL;
    mo_u8 i;
    mo_u16 active_index = 0, null_index = 0;

    for (i = 0; i < btn_tsk.vk_number; i++) {
        if (btn_tsk.btn_widget_set[i].vk_code == VK_CODE_NULL) {
            if (!null_index) null_index = i + 1;
        }
        if (btn_tsk.btn_widget_set[i].vk_code == vk_c) {
            active_index = i + 1;
            break;
        }
    }

    if (active_index) {
        widget = &btn_tsk.btn_widget_set[active_index - 1];
    } else if (null_index) {
        widget = &btn_tsk.btn_widget_set[null_index - 1];
    }

    return widget;
}

void mo_send_a_vk_to_btn_task(mo_msg_id id, mo_u8 vk_code) {
    mo_u8 *msg = (mo_u8 *)mo_malloc(sizeof(mo_u8));
    if (msg != NULL) {
        *msg = vk_code;
        mo_msg_send(&btn_tsk.tsk, id, msg, 0);
    }
}

static void send_btn_msg(mo_vk_code_t code, mo_btn_pattern_t btn_patt, mo_u8 click_num) {
    mo_key_event_msg_t *msg = (mo_key_event_msg_t *)mo_malloc(sizeof(mo_key_event_msg_t));
    if (msg != NULL) {
        msg->vk_code = code;
        msg->vk_patt = btn_patt;
        msg->click_num = click_num;
        mo_msg_send(btn_tsk.client_tsk, SYS_KEY_EVENT, msg, 0);
    }
}

static void send_hold_vk_msg(btn_widget_t *widget, mo_btn_pattern_t btn_patt) {
    if (widget->vk_state == MO_VK_DW) {
        send_btn_msg(widget->vk_code, btn_patt, 0);
    } else {
        widget->click_cnt = 0;
        widget->vk_code = VK_CODE_NULL;
    }
}

static void mo_button_handle(mo_task tsk, mo_msg_id id, mo_msg msg) {
    mo_vk_code_t vk_code;
    btn_widget_t *widget;
    mo_btn_pattern_t bt_patt;
    switch (id) {
        case SYS_EVENT_BUTTON_LOOP: {
            mo_u8 i;
            mo_u8 no_vk_process = 1;

            for (i = 0; i < btn_tsk.vk_number; i++) {
                widget = &btn_tsk.btn_widget_set[i];
                if (widget->vk_code != VK_CODE_NULL) {
                    no_vk_process = 0;
                    widget->hold_cnt++;
                    // MO_LOG("widget->hold_cnt %d \r\n",widget->hold_cnt);
                    if (widget->hold_cnt == btn_timeing.m_click_tim) {
                        if (widget->vk_state == MO_VK_UP) {
                            if (widget->click_cnt) {
                                if (widget->click_cnt == 1) {
                                    bt_patt = BTN_SINGLE_CLICK;
                                } else {
                                    bt_patt = BTN_MULTI_CLICK;
                                }
                                send_btn_msg(widget->vk_code, bt_patt, widget->click_cnt);
                            }
                            widget->click_cnt = 0;
                            widget->vk_code = VK_CODE_NULL;
                        }
                    } else if (widget->hold_cnt == btn_timeing.lp_tim) {
                        send_hold_vk_msg(widget, BTN_LP);
                    } else if (widget->hold_cnt == btn_timeing.vlp_tim) {
                        send_hold_vk_msg(widget, BTN_VLP);
                    } else if (widget->hold_cnt == btn_timeing.vvlp_tim) {
                        send_hold_vk_msg(widget, BTN_VVLP);
                    } else if (widget->hold_cnt == btn_timeing.vvvlp_tim) {
                        send_hold_vk_msg(widget, BTN_VVVLP);
                    } else if (widget->hold_cnt == btn_timeing.vvvvlp_tim) {
                        send_hold_vk_msg(widget, BTN_VVVVLP);
                    } else if (widget->hold_cnt > btn_timeing.vvvvlp_tim) {
                        widget->vk_code = VK_CODE_NULL;
                    }
                }
            }

            if (!no_vk_process) {
                mo_msg_send(tsk, SYS_EVENT_BUTTON_LOOP, 0, BTN_LOOP_INTERVAL);
            } else {
                btn_tsk.processing = FALSE;
                // mo_msg_cancel_all(tsk,SYS_EVENT_BUTTON_LOOP);
                MO_LOG("btn_tsk.processing =  %d \r\n", btn_tsk.processing);
            }

        } break;
        case SYS_EVENT_VK_UP:
            // MO_LOG("SYS_EVENT_VK_UP \r\n");
            if (msg != NULL) {
                mo_u8 i;
                vk_code = *(mo_vk_code_t *)msg;
                for (i = 0; i < btn_tsk.vk_number; i++) {
                    if (btn_tsk.btn_widget_set[i].vk_code == vk_code) {
                        widget = &btn_tsk.btn_widget_set[i];

                        widget->vk_code = vk_code;

                        if (widget->hold_cnt < btn_timeing.m_click_tim) widget->click_cnt++;

                        if (widget->vk_state != MO_VK_UP) {
                            widget->vk_state = MO_VK_UP;
                            widget->hold_cnt = 0;
                            send_btn_msg(vk_code, BTN_UP, 0);
                        }
                    }
                    break;
                }
            }
            break;
        case SYS_EVENT_VK_DOWN:
            // MO_LOG("SYS_EVENT_VK_DOWN \r\n");
            if (msg != NULL) {
                vk_code = *(mo_vk_code_t *)msg;
                widget = mo_get_vk_widget_by_code(vk_code);
                if (widget != NULL) {
                    if (widget->vk_code == VK_CODE_NULL) {
                        widget->click_cnt = 0;
                        widget->hold_cnt = 0;
                    }
                    if (widget->vk_state != MO_VK_DW) {
                        widget->vk_state = MO_VK_DW;
                        widget->hold_cnt = 0;
                        // MO_LOG("vk code :%d \r\n",vk_code);
                        send_btn_msg(vk_code, BTN_DOWN, 0);
                    }
                    widget->vk_code = vk_code;

                    if (btn_tsk.processing == FALSE) {
                        btn_tsk.processing = TRUE;
                        mo_msg_cancel_all(tsk, SYS_EVENT_BUTTON_LOOP);
                        mo_msg_send(tsk, SYS_EVENT_BUTTON_LOOP, 0, BTN_LOOP_INTERVAL);
                    }
                }
            }
            break;
        default:

            break;
    }
}

#if 0
mo_u8 mo_btn_register_vk(mo_vk_code_t vk_code){
    btn_unit_t *btn_uint;
    mo_u8 ret=FALSE;

    btn_uint = (btn_unit_t*)mo_malloc(sizeof(btn_unit_t));
    if(btn_uint != NULL){

        ret = dlist_ins_next(&btn_tsk.btn_list,btn_tsk.btn_list.head,\
						    &btn_uint->btn_elmt,&btn_uint->btn_widget);
    }
    

    return ret;
}
#else

mo_u8 mo_btn_register_vk_set(btn_widget_t *widget_set, mo_u8 vk_number) {
    // btn_widget_t *widget_set=NULL;
    mo_u8 ret = FALSE;

    if (widget_set != NULL) {
        // widget_set = (btn_widget_t*)mo_malloc((sizeof(btn_widget_t)*vk_number));

        btn_tsk.btn_widget_set = widget_set;
        btn_tsk.vk_number = vk_number;
        ret = TRUE;

        MO_LOG("vk number: %d \r\n", btn_tsk.vk_number);
    }

    return ret;
}
#endif

/*!
  @brief init the button task, and register a client task to receive the input
  event by user.
  @param client_tsk: point to a client task that will be receiving the input
  event.
  @return   FALSE: failed
                TRUE: successfully
*/
mo_u8 mo_btn_init(mo_task client_tsk) {
    mo_u8 ret = FALSE;
    btn_tsk.tsk.handler = mo_button_handle;

    if (client_tsk != NULL) {
#if (HW_NUMBER_)
        btn_tsk.client_tsk = client_tsk;
        ret = mo_btn_register_vk_set(btn_widget, (HW_NUMBER_));
#endif
    }

    /*
    btn_tsk.btn_list.size = 0;
    btn_tsk.btn_list.head = NULL;
    btn_tsk.btn_list.tail = NULL;*/
    return ret;
}
